Scripting is an app that allows you to create iOS Home Screen widgets using TypeScript and React-like TSX syntax.
You can define your widget’s UI inside a widget.tsx file using SwiftUI-inspired components.
widget.tsx Filewidget.tsx.scripting package.Calling Widget.present() renders the widget on the Home Screen.
You can use the following Widget API properties to adapt layout and content:
| Property | Description |
|---|---|
Widget.displaySize |
The actual pixel size of the widget at runtime. |
Widget.family |
The widget size: 'small', 'medium', or 'large'. |
Widget.parameter |
The user-defined custom parameter configured in the Home Screen widget settings. |
These properties help you dynamically adjust content and layout based on the widget’s size or user preferences.
Once configured, the UI defined in your widget.tsx file will appear directly on the Home Screen.
Use SwiftUI-inspired built-in components such as VStack, HStack, Text, and Image to compose your widget UI.
You can also separate logic and UI across multiple files and import them as needed.
While you can technically use React hooks such as useState or useEffect, they don’t take effect inside widgets because widgets are rendered once and have no persistent interactive lifecycle.
Avoid relying on dynamic state logic.
iOS enforces an approximate 30 MB memory limit per widget. To stay within it:
If a widget fails to render or appears blank, it’s often due to exceeding this limit.
After calling Widget.present(...), the current execution context is immediately destroyed:
Widget.present().Widget.present(), as it will never run.Although widgets are mostly static, basic interactivity can be achieved via AppIntent:
<Button> or <Toggle> components to trigger AppIntents.Not all SwiftUI views are supported in WidgetKit. Some layout containers and visual effects are unavailable. Refer to Apple’s official documentation: Supported SwiftUI views in WidgetKit.
Widget previews inside the Scripting app are only approximations. The actual rendering on the Home Screen may differ slightly in:
Always test on the Home Screen to verify the final layout.
Widget.reloadAll() to refresh all widgets (both user and developer kinds).index.tsx or inside an AppIntent.This enables rapid iteration on layout and logic.
Scripting now distinguishes between two kinds of widgets:
| Type | Description |
|---|---|
| User Widgets | Regular widgets intended for end-users to add and use on the Home Screen. |
| Test Widgets | Developer-only widgets used for debugging and previewing during development. |
Each kind has its own kind identifier, allowing isolation between user and developer widgets.
This ensures that refreshing test widgets doesn’t affect the user’s actual widgets.
| Method | Description |
|---|---|
Widget.reloadUserWidgets() |
Refreshes User Widgets only, without affecting any developer Test Widgets. |
Widget.reloadTestWidgets() |
Refreshes Test Widgets only, without affecting user widgets on the Home Screen. |
These methods were introduced to isolate user and developer environments. When developing, refreshing Test Widgets won’t disturb any user widgets already installed.
Widget.reloadTestWidgets() for testing.Widget.reloadUserWidgets() or Widget.reloadAll().This separation helps prevent interference between development experiments and user-facing widgets.
Widget.preview for In-App Development PreviewDuring development, you can use Widget.preview() in your index.tsx to preview layout and parameter configurations without leaving the app.
Widget.preview(options)This method simulates widget rendering for various sizes and parameters, suitable for development-only testing.
It can only be called from the index.tsx environment (not from widget.tsx or intent.tsx).
| Property | Type | Description |
|---|---|---|
family |
'systemSmall' |
'systemMedium' |
parameters.options |
Record<string, string> |
Key–value map of parameter options. Values must be JSON-parsable strings. |
parameters.default |
string |
Specifies which parameter option to use by default. |
This allows testing visual differences under different parameter inputs such as colors, text, or layout configurations.
index.tsx — not from widget.tsx or intent.tsx.